////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   BeanValidator.java
// AUTHOR           :   ric.yik
// DATE CREATE      :   2006/5/2
// DESCRIPTION      :   
//                  :   
//                  :   
//                  :   
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// 2006/05/02   Ric Yik         1.0                 source is created.
// 2006/05/22   Ric Yik         1.0                 BugZilla #5770
//
//
////////////////////////////////////////////////////////////////////////////////

package com.erp.app.util.web;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;

import com.erp.framework.SimpleConstants;
import com.erp.framework.controller.form.MultiRow;
import com.erp.framework.controller.form.SimpleCoreForm;
import com.erp.framework.model.schema.MetaData;
import com.erp.framework.model.schema.TableSchema;
import com.erp.framework.util.CommonUtil;
import com.erp.framework.util.logger.Logger;

public class BeanValidator {

    public boolean validate(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response, ActionErrors errors) {
        return this.validate(formIn, formIn, "", "", errors);
    }

    public boolean validate(Object bean, ActionForm formIn, String tabObjectId, String line, ActionErrors errors) {
        TableSchema ts = WebUtil.findTs(bean, (SimpleCoreForm) formIn);
        if (ts == null) {
            throw new NullPointerException("Error validating bean of type " + bean.getClass() + ": ts is null.\n bean.toString(): " + CommonUtil.getString(bean));
        }
        for (Iterator metadatas = ts.getTs().iterator(); metadatas.hasNext();) {
            MetaData metadata = (MetaData) metadatas.next();
            String webLabelName = metadata.getWebLabelName();
            if (metadata.getVoPropertyName().startsWith("srch")) {
                if (metadata.getVoPropertyName().endsWith("To")) {
                    webLabelName += " To";
                }
            }
            String label = (CommonUtil.isEmpty(tabObjectId) ? "" : ((SimpleCoreForm) formIn).getTs().getTabLabelByObjectId(tabObjectId)) + webLabelName + ((CommonUtil.isEmpty(line)) ? "" : line);
            try {
                PropertyDescriptor property = PropertyUtils.getPropertyDescriptor(bean, metadata.getVoPropertyName());
                if (property != null && property.getReadMethod() != null) {
                   if (!property.getPropertyType().equals(String.class)) continue;
                    String value = CommonUtil.nullToString(property.getReadMethod().invoke(bean, new Object[] {}));
                    if (!metadata.isNullable() && !metadata.isAutoGenerated()) {
                        if (!WebUtil.validateNonBlankField(value, label, errors)) continue;
                    } else {
                        if (CommonUtil.isEmpty(value)) continue;
                    }
                    Class propertyClass = Class.forName(metadata.getColumnClassName());
                    if (Integer.class.isAssignableFrom(propertyClass) || BigInteger.class.isAssignableFrom(propertyClass)) {
                        boolean validInteger = false;
                        if (metadata.isPositiveNumeric()) {
                            validInteger = WebUtil.validatePositiveInteger(value, label, metadata.isNullable(), errors);
                        } else if (metadata.isNegativeNumeric()) {
                            validInteger = WebUtil.validateNegativeInteger(value, label, metadata.isNullable(), errors);
                        } else if (metadata.isNonnegativeNumeric()) {
                            validInteger = WebUtil.validateNonnegativeInteger(value, label, metadata.isNullable(), errors);
                        } else {
                            validInteger = WebUtil.validateValidInteger(value, label, metadata.isNullable(), errors);
                        }
                        if (validInteger) {
                            WebUtil.validatePrecisionScale(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        }
                    } else if (BigDecimal.class.isAssignableFrom(propertyClass) || Number.class.isAssignableFrom(propertyClass)) {
                        boolean validNumber = false;
                        if (metadata.isPositiveNumeric()) {
                            validNumber = WebUtil.validatePositiveNumber(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        } else if (metadata.isNegativeNumeric()) {
                            validNumber = WebUtil.validateNegativeNumber(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        } else if (metadata.isNonnegativeNumeric()) {
                            validNumber = WebUtil.validateNonnegativeNumber(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        } else {
                            validNumber = WebUtil.validateValidNumber(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        }
                        if (validNumber) {
                            WebUtil.validatePrecisionScale(value, metadata.getColumnPrecision(), metadata.getColumnScale(), label, metadata.isNullable(), errors);
                        }
                    } else if (Timestamp.class.isAssignableFrom(propertyClass)) {
                        WebUtil.validateDate(CommonUtil.dateToString(CommonUtil.stringToTimestamp(value), SimpleConstants.INPUT_DATE_FORMAT), label, metadata, errors);
                    } else if (Date.class.isAssignableFrom(propertyClass)) {
                        WebUtil.validateDate(value, label, metadata, errors);
                    } else if (String.class.isAssignableFrom(propertyClass)) {
                        if (metadata.isCode()) {
                            WebUtil.validateCode(value, label, errors, metadata.isSpaceAllowed());
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                Logger.logExceptions(this, e);
                throw new RuntimeException(e.getMessage());
            } catch (InvocationTargetException e) {
                Logger.logExceptions(this, CommonUtil.getTargetExecption(e));
                throw new RuntimeException(e.getMessage());
            } catch (NoSuchMethodException e) {
                Logger.debug(this, "No such property: " + metadata.getVoPropertyName());
                continue;
            } catch (ClassNotFoundException e) {
                Logger.logExceptions(this, e);
            }
        }
//        if (errors.size() == 0) {
//            for (Iterator ranges = CommonUtil.getIterator(ts.getRanges().values()); ranges.hasNext();) {
//            }
//        }
        return (errors.size() == 0);
    }

    public boolean validateMultiRows(ActionMapping mapping, ActionForm formIn, HttpServletRequest request, HttpServletResponse response, ActionErrors errors, List list, MultiRowValidator validator) {
        for (Iterator rows = list.iterator(); rows.hasNext();) {
            MultiRow row = (MultiRow) rows.next();
            if (WebUtil.isValidationSkippable(row)) continue;
            if (this.validate(row, formIn, validator.getTabLabelObjectId(), ActionErrorUtil.ERROR_CHILD_IND + validator.getLineNumber(mapping, formIn, request, response, errors, row), errors) 
                    || !validator.isSkipMoreValidateOnError(row, errors)) {
                validator.moreValidate(mapping, formIn, request, response, errors, row);
            }
        }
        return (errors.size() == 0);
    }

}
